/*
 *  Main authors:
 *     Gustavo Gutierrez <ggutierrez@cic.puj.edu.co>
 *     Alberto Delgado <adelgado@cic.puj.edu.co>
 *
 *  Contributing authors:
 *     Alejandro Arbelaez <aarbelaez@puj.edu.co>
 *
 *  Copyright:
 *     Gustavo Gutierrez, 2006
 *     Alberto Delgado, 2006
 *
 *  Last modified:
 *     $Date$
 *     $Revision$
 *
 *  This file is part of GeOz, a module for integrating gecode 
 *  constraint system to Mozart: 
 *     http://home.gna.org/geoz
 *
 *  See the file "LICENSE" for information on usage and
 *  redistribution of this file, and for a
 *     DISCLAIMER OF ALL WARRANTIES.
 *
 */

#ifndef __GEOZ_INT_PROP_BUILTINS_CC__
#define __GEOZ_INT_PROP_BUILTINS_CC__

#include "GeIntProp-builtins.hh"

using namespace Gecode;
using namespace Gecode::Int;

OZ_BI_define(int_eq,3,0)
{
 //Both spaces must be the same
  
  IntVar v1,v2;
  GenericSpace *gesp1;   
  int consistencyLevel; 
  //printf("int_eq\n");fflush(stdout);
  if(!OZ_isInt(OZ_in(2)))
      RAISE_EXCEPTION("The last value must be the consistency level");
    
  consistencyLevel=OZ_intToC(OZ_in(2));
  if (!OZ_isGeIntVar(OZ_in(0)))
      RAISE_EXCEPTION("The first argument must be GeIntVar");
    
  //  gesp1 = get_Space(OZ_in(0));
  v1 = get_IntVar(OZ_in(0));
  gesp1 = extVar2Var(get_GeIntVar(OZ_in(0)))->getBoardInternal()->getGenericSpace();

  if(OZ_isInt(OZ_in(1)))
    {       
      int domain=OZ_intToC(OZ_in(1));
      IntVar geint2(gesp1,domain,domain);
      v2 = geint2;      
    }
  else if(!OZ_isGeIntVar(OZ_deref(OZ_in(1)))){
    RAISE_EXCEPTION("The second argument must be either Int or GeIntVar ");}
  else
    {
      v2 = get_IntVar(OZ_in(1));
      if(!(gesp1 == extVar2Var(get_GeIntVar(OZ_in(1)))->getBoardInternal()->getGenericSpace()))
	RAISE_EXCEPTION("The variables are not in the same space");
    }	

  try{
    eq(gesp1,v1,v2,(IntConLevel)consistencyLevel);
     //gesp1->setUnstable();
    unsigned int a;
    //gesp1->status(a);
    return PROCEED;
  } catch (Exception e) {
    return OZ_raiseC("prop: int_eq",0);
  }
} OZ_BI_end


OZ_BI_define(int_rel,4,0)
{
  
  //  IntVar v1,v2;
  //  GenericSpace *gesp1;   
  DeclareGSpace(gesp1);
  int consistencyLevel,relType; 
  //printf("int_rel\n");fflush(stdout);  
  if(!OZ_isInt(OZ_in(3))) {
    RAISE_EXCEPTION("The last value must be the consistency level: relProp");
  }
  consistencyLevel=OZ_intToC(OZ_in(3));
  
  if(!OZ_isInt(OZ_in(1))) {
    RAISE_EXCEPTION("The second argument has to be a Relation Type: relProp");
  }
  relType=OZ_intToC(OZ_in(1));
  /*  if (!OZ_isGeIntVar(OZ_in(0))) {
    RAISE_EXCEPTION("The first argument must be GeIntVar: relProp");
    }*/
  DeclareGeIntVar(0,v1,gesp1);
  DeclareGeIntVar(2,v2,gesp1);
  //gesp1 = get_Space(OZ_in(0));
  //  v1 = get_IntVar(OZ_in(0));
  //  gesp1 = extVar2Var(get_GeIntVar(OZ_in(0)))->getBoardInternal()->getGenericSpace();
  
  /*  if(OZ_isInt(OZ_in(2))) {       
    int domain=OZ_intToC(OZ_in(2));
    IntVar geint2(gesp1,domain,domain);
    v2 = geint2;      
  }
  else if(!OZ_isGeIntVar(OZ_deref(OZ_in(2)))) {
    RAISE_EXCEPTION("The second argument must be either Int or GeIntVar: relProp");
  }
  else {
    v2 = get_IntVar(OZ_in(2));
    if(!(gesp1 == extVar2Var(get_GeIntVar(OZ_in(2)))->getBoardInternal()->getGenericSpace()))
      RAISE_EXCEPTION("The variables are not in the same space: relProp");
      }	*/

  try {
    rel(gesp1,v1,(IntRelType)relType,v2,(IntConLevel)consistencyLevel);
    //gesp1->setUnstable();
    unsigned int a;
    //gesp1->status(a);
    return PROCEED;
  } catch (Exception e) {
    return OZ_raiseC("prop: int_rel",0);
  }
} OZ_BI_end


OZ_BI_define(int_dist,2,0)
 {
   DECLARE_INTVARARRAY(var,0);   
   //printf("int_dist\n");fflush(stdout);
   OZ_declareInt(1,conlevel);
   try {
     distinct(sp,var,(IntConLevel)conlevel);
     //sp->setUnstable();
     unsigned int a;
     //sp -> status(a);
     //printf("status del espacio de gecode: %d ",sp -> status(a));fflush(stdout);
     return PROCEED;
   } catch(Exception e){
     return OZ_raiseC("prop: distinc",0);
   }
   
 } OZ_BI_end


 OZ_BI_define(int_dist2,3,0)
 {
   DECLARE_INTARGS(arguments,0);
   DECLARE_INTVARARRAY(var,1);
   //printf("int_dist2\n");fflush(stdout);
   OZ_declareInt(2,conlevel);
   try {
     distinct(sp,arguments,var,(IntConLevel)conlevel);
     //sp->setUnstable();
     unsigned int a;
     
     
     return PROCEED;
   } catch(Exception e){
     return OZ_raiseC("prop: distinc",0);
   }
   
 } OZ_BI_end



// //Propagador lineal simple
// //La suma de los elementos del arreglo(x1) debe ser igual a (x3 int o IntVar)
 OZ_BI_define(int_linear,4,0)
 {
   DECLARE_INTVARARRAY(x1,0);
   //printf("int_linear\n");fflush(stdout);
   OZ_declareInt(1,x2);
   OZ_declareInt(3,x4);	   
   if(!OZ_isInt(OZ_deref(OZ_in(2)))) {
     try{
       linear(sp,x1,(IntRelType)x2,get_IntVar(OZ_in(2)),(IntConLevel)x4);
       //sp->setUnstable();
       return PROCEED;
     } catch(Exception e){
       return OZ_raiseC("prop: linear",0);
     }
   }
   else{
     OZ_declareInt(2,x3);
     try{
       linear(sp,x1,(IntRelType)x2,x3,(IntConLevel)x4);
       //sp->setUnstable();
       return PROCEED;
     } catch(Exception e){
       return OZ_raiseC("prop: linear",0);
     }
   }        
 } OZ_BI_end
 
// //Propagador un poco linear un poco mas complicado
 OZ_BI_define(int_linear2,5,0)
 {
   DECLARE_INTARGS(arguments,0);
   DECLARE_INTVARARRAY(array_var,1);
   //printf("int_linear2\n");fflush(stdout);
   OZ_declareInt(2,rel);
   OZ_declareInt(4,con);

   if(!OZ_isInt(OZ_deref(OZ_in(3)))) {
     try{
       linear(sp,arguments,array_var,(IntRelType)rel,get_IntVar(OZ_in(3)),(IntConLevel)con);
         //sp->setUnstable();
       unsigned int a;
       //sp -> status(a);
       return PROCEED;
     } catch(Exception e){
       //       return OZ_raiseC("prop: linear2",0);
       RAISE_GE_EXCEPTION(e);
     }
   }
   else {
     OZ_declareInt(3,val);
     try{
       linear(sp,arguments,array_var,(IntRelType)rel,val,(IntConLevel)con);
       //sp->setUnstable();
       unsigned int a;
       //sp -> status(a);
       return PROCEED;
     } catch(Exception e){
       //       return OZ_raiseC("prop: linear2",0);
       RAISE_GE_EXCEPTION(e);
     }
   }
 } OZ_BI_end
 
 OZ_BI_define(space_status,0,0)
 {
   unsigned int a;
   ///printf("antes--------------------------------------------------------------\n%d",oz_currentBoard()->getGenericSpace()->status(a));fflush(stdout);
   
   //printf("--------------------------------------------------------------\n");fflush(stdout);
       return PROCEED;
 }OZ_BI_end


OZ_BI_define(int_linearR,5,0)
{
  DECLARE_INTVARARRAY(array_var,0);

  OZ_declareInt(1,relType);
  OZ_declareInt(4,conLevel);

  DeclareGeIntVar(2,v2,sp);
  DeclareGeIntVar(3,v3,sp);

  try{
    linear(sp,array_var,(IntRelType)relType,v2,static_cast<BoolVar>(v3),(IntConLevel)conLevel);
  }
  catch(Exception e) {
    // return OZ_raiseC("prop: int_linearR:",0);
    RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;
    
} OZ_BI_end


OZ_BI_define(int_linearCR,6,0)
{

  DECLARE_INTARGS(array_arg,0);
  DECLARE_INTVARARRAY(array_var,1);
  
  OZ_declareInt(2,relType);
  OZ_declareInt(5,conLevel);
  
  DeclareGeIntVar(3,v3,sp);
  DeclareGeIntVar(4,v4,sp);

  try{
    linear(sp,array_arg,array_var,(IntRelType)relType,v3,static_cast<BoolVar>(v4),(IntConLevel)conLevel);
  }
  catch(Exception e){
    RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;

} OZ_BI_end


OZ_BI_define(int_count,5,0)
{
  DECLARE_INTVARARRAY(arreglo,0);
  IntVar x1,x3;
  OZ_declareInt(2,rl);
  OZ_declareInt(4,cl);
  
  if(OZ_isGeIntVar(OZ_deref(OZ_in(1))))
    x1 = get_IntVar(OZ_in(1));
  else if (OZ_isInt(OZ_in(1))) {
    OZ_declareInt(1,valTmp);
    IntVar tmp(sp,valTmp,valTmp);
    x1 = tmp;
  }
  else
    RAISE_EXCEPTION("The second argument must be either Int or GeIntVar");
  
  if(OZ_isGeIntVar(OZ_deref(OZ_in(3))))
    x3 = get_IntVar(OZ_in(3));
  else if (OZ_isInt(OZ_in(3))) {
    OZ_declareInt(3,valTmp);
    IntVar tmp(sp,valTmp,valTmp);
    x3 = tmp;
  }
  else
    RAISE_EXCEPTION("The threeth argument must be either Int or GeIntVar");
  try {
    count(sp,arreglo,x1,(IntRelType)rl,x3,(IntConLevel)cl);
  }
  catch(Exception e) {
   RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;

} OZ_BI_end

OZ_BI_define(int_mult,3,0)
{
  DeclareGSpace(sp);
  DeclareGeIntVar(0,v1,sp);
  DeclareGeIntVar(1,v2,sp);
  DeclareGeIntVar(2,v3,sp);
  try{
    mult(sp,v1,v2,v3);
  } catch(Exception e) {
    RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;
} OZ_BI_end


OZ_BI_define(int_Gabs,3,0)
{
  //  GenericSpace *sp;
  //  IntVar v0,v1;
  DeclareGSpace(sp);
  DeclareGeIntVar(0,v0,sp);
  DeclareGeIntVar(1,v1,sp);
  OZ_declareInt(2,conLevel);

  /*if(OZ_isGeIntVar(OZ_in(0))) sp= get_Space(OZ_in(0));
  if(sp == NULL && OZ_isGeIntVar(OZ_in(1))) sp = get_Space(OZ_in(1));
  if(sp == NULL) 
    RAISE_EXCEPTION("At list one variable must be a GeIntVar");
  */
  /*  if(OZ_isInt(OZ_in(0))) {
    OZ_declareInt(0,domain);
    IntVar _tmp(sp,domain,domain);
    v0 = _tmp;
  }
  else if(OZ_isGeIntVar(OZ_in(0))) {
    v0 = get_IntVar(OZ_in(0));
    if(sp != get_Space(OZ_in(0))) 
      RAISE_EXCEPTION("The variables are not in the same space");
  }
  else RAISE_EXCEPTION("The variables are not in the same space ");
  */
  /*if(OZ_isInt(OZ_in(1))) {
    OZ_declareInt(1,domain);
    IntVar _tmp(sp,domain,domain);
    v1 = _tmp;
  }
  else if(OZ_isGeIntVar(OZ_in(1))) {
    v1 = get_IntVar(OZ_in(1));
    if(sp != get_Space(OZ_in(1)))
      RAISE_EXCEPTION("The variables are not in the same space");
  }
  else RAISE_EXCEPTION("The variables are not in the same space ");
  */
  try{
    Gecode::abs(sp,v0,v1,(IntConLevel)conLevel);
  }
  catch(Exception e) {
    RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;
    
} OZ_BI_end

OZ_BI_define(bool_and,4,0)
{
  //  IntVar v1,v2,v3;
  //  GenericSpace *sp;
  DeclareGSpace(sp);
  DeclareGeIntVar(0,v1,sp);
  DeclareGeIntVar(1,v2,sp);
  DeclareGeIntVar(2,v3,sp);
  OZ_declareInt(3,ConLevel);
  //int ConLevel;
  
  /*  if(OZ_isGeIntVar(OZ_in(0))) sp = get_Space(OZ_in(0));
  if(sp != NULL && OZ_isGeIntVar(OZ_in(1))) sp = get_Space(OZ_in(1));
  if(sp != NULL && OZ_isGeIntVar(OZ_in(2))) sp = get_Space(OZ_in(2));
  if(sp != NULL && OZ_isGeIntVar(OZ_in(3))) sp = get_Space(OZ_in(3));
  if(sp != NULL && OZ_isGeIntVar(OZ_in(4))) sp = get_Space(OZ_in(4));
  if(sp == NULL)
    RAISE_EXCEPTION("At list one variable must be a GeIntVar");
  */
  /*if(OZ_isInt(OZ_in(0))) {
    int domain = OZ_intToC(OZ_in(0));
    IntVar Tmp1(sp,domain,domain);
    v1 = Tmp1;
  }
  else if(OZ_isGeIntVar(OZ_deref(OZ_in(0)))) {
    v1 = get_IntVar(OZ_in(0));
    if(!(sp == get_Space(OZ_in(0))))
      RAISE_EXCEPTION("The variables are not in the same space");
  }
  else RAISE_EXCEPTION("The first variable must be either Int or GeIntVar");


  if(OZ_isInt(OZ_in(1))) {
    int domain = OZ_intToC(OZ_in(1));
    IntVar Tmp1(sp,domain,domain);
    v2 = Tmp1;
  }
  else if(OZ_isGeIntVar(OZ_deref(OZ_in(1)))) {
    v2 = get_IntVar(OZ_in(1));
    if(!(sp == get_Space(OZ_in(1))))
      RAISE_EXCEPTION("The variables are not in the same space");
  }
  else RAISE_EXCEPTION("The first variable must be either Int or GeIntVar");


  if(OZ_isInt(OZ_in(2))) {
    int domain = OZ_intToC(OZ_in(2));
    IntVar Tmp1(sp,domain,domain);
    v3 = Tmp1;
  }
  else if(OZ_isGeIntVar(OZ_deref(OZ_in(2)))) {
    v3 = get_IntVar(OZ_in(2));
    if(!(sp == get_Space(OZ_in(2))))
      RAISE_EXCEPTION("The variables are not in the same space");
  }
  else RAISE_EXCEPTION("The first variable must be either Int or GeIntVar");
  */
  /*  if(OZ_isInt(OZ_in(3))) {
    ConLevel = OZ_intToC(OZ_in(3));
  }
  else RAISE_EXCEPTION("The last argument must be Int");
  */
  try{
    mult(sp,static_cast<BoolVar>(v1),static_cast<BoolVar>(v2),static_cast<BoolVar>(v3),(IntConLevel)ConLevel);
  }
  catch(Exception e){
    RAISE_GE_EXCEPTION(e);
  }
  return PROCEED;

} OZ_BI_end

#endif
